/*
 * ConnectionDescription.java
 * 
 * last update: 30.01.2010 by Vlad Badoiu
 * 
 * author:	Vlad Badoiu(vladbadoiu@gmail.com)
 *
 * Obs:
 */

package engine;

import middle.*;
import java.util.*;

/**
 * A connection from inside a module to the outside world.
 * It may contain a selection of ports bundled together under a 
 * single name visible from outside or an expression to be assigned to
 * the port designated by the name (in a named parameter list).
 */
@SuppressWarnings("serial")
class ConnectionDescription extends Symbol{

	/**
	 * The in/out/both type of the connection
	 */
	int type;

	/**
	 * The ports bundled inside this name
	 */
	ExpressionDescription portExpDesc;

	boolean preparedForContSelection;

	ConnectionDescription(String name, int lineNo,
			ExpressionDescription portExpDesc){
		super(name, lineNo);
		this.portExpDesc = portExpDesc;
	}

	/**
	 * If this expression is a port selection, computes the overall type:
	 *     if all ports have tha same type with the exception of the inuout ones,
	 *        the overall type is the same. If all the ports are inout, the
	 *        overall is inout.
	 * Note that the if a port identifier is from another module (a fqn with more
	 * than one node), a parse exception is thrown
	 *     else, an exception is thrown
	 */
	int computeType(DefaultNameSpaceDescription nsd) throws ParseException {
		// verifies that all the ports have comaptible types
		PortDescription pd;
		try{
			GenericSelectorDescription gsd = (GenericSelectorDescription) portExpDesc;
			if((pd = nsd.isPort((String) gsd.fqn.node)) != null)
				return type = pd.type;
			throw new ParseException (":error : bad port expression : \"" +
					gsd.fqn + "\" is not a port");
		} catch (ClassCastException cex) {}
		try {
			for(Enumeration<ExpressionDescription> e =
				((SelectionExpressionDescription)portExpDesc).elements() ;
			e.hasMoreElements() ; )
			{
				GenericSelectorDescription ck =
					(GenericSelectorDescription)e.nextElement();
				if((pd = nsd.isPort((String) ck.fqn.node)) != null){
					if(type == PortDescription.none)type = pd.type;
					else
						if(!((pd.type == type) ||
								(pd.type == PortDescription.inout) ||
								(type == PortDescription.inout)))
							throw new ParseException(":error : bad port expression : \"" +
									pd.name
									+ "\" and \"" + name +
							"\" types do not match");
				}else
					throw new ParseException(nsd.toString(lineNo) +
							":error : bad port expression : \"" +
							nsd.name + "\" is not a port");
			}
		} catch (ClassCastException cex) {
			throw new ParseException( ":error: bad port expression : not a port selection");
		}
		return type;
	}

	Object instantiate(NameSpace ns, ScopeNode thisScope)throws ParseException{
		Expression exp;

		if (portExpDesc == null) { //fake connection ?
			type = PortDescription.inout;
			return null;
		}

		try{
			exp = portExpDesc.instantiate(ns);
		}catch(ParseException ex){
			xConsole.dumpStack(ex);
			throw new ParseException(ns.desc.toString(lineNo) + ex);
		}

		return exp;
	}

	/**
	 * Makes this expression a continuous expression
	 */
	void prepareForContSelection()throws ParseException{
		if(preparedForContSelection)return;
		preparedForContSelection = true;
		try{
			((AssignableSelection)portExpDesc).toContSelection();
		}catch(ClassCastException ex){
			throw new ParseException(" error: \"" + name +
			"\" cannot be input");
		}
	}

	public int getType(){
		return connType;
	}
}



